/* line_chart.c
 * 功能：在 (5,5)~(230,180) 区域绘制折线图
 * 折线满屏后仅清除折线，保留坐标轴与标题
 */
#include "line_chart.h"
#include "tftspi.h"
#include <string.h>

/* 折线图区域（左上角和右下角） */
#define CHART_X0    5          /* 折线图左上角 X */
#define CHART_Y0    5          /* 折线图左上角 Y */
#define CHART_W     (230 - CHART_X0)   /* 折线宽度 = 230-5 = 225 */
#define CHART_H     (180 - CHART_Y0)   /* 折线高度= 180-5 = 175 */

/* 其余常数 */
#define VREF_MAX    3300
#define PIX_PER_SEC (CHART_W / 60)     /* 每秒钟横向像素数 */

/* 颜色 */
#define AXIS_COLOR   0x00FF00  /* 坐标轴绿色 */
#define TITLE_COLOR  0xFFFF00  /* 标题黄色   */
#define LINE_COLOR   0xFFFFFF  /* 折线白色   */

/* 上一次采样点 */
static uint16_t x_last = 0;
static uint16_t y_last = CHART_Y0 + CHART_H / 2;
static uint16_t x_cur  = 0;

/*---------------- 画点（仅折线区） ----------------*/
static inline void lcd_putpixel(uint16_t x, uint16_t y, uint32_t color)
{
    TFT_SEND_CMD(0x2A);
    TFT_SEND_DATA((x) >> 8); TFT_SEND_DATA(x);
    TFT_SEND_DATA((x) >> 8); TFT_SEND_DATA(x);
    TFT_SEND_CMD(0x2B);
    TFT_SEND_DATA((y) >> 8); TFT_SEND_DATA(y);
    TFT_SEND_DATA((y) >> 8); TFT_SEND_DATA(y);
    TFT_SEND_CMD(0x2C);
    TFT_SEND_DATA(color >> 16);
    TFT_SEND_DATA(color >> 8);
    TFT_SEND_DATA(color);
}

/*---------------- Bresenham 画线 ----------------*/
static void draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color)
{
    int dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
    int dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
    int err = dx + dy, e2;
    while (1) {
        lcd_putpixel(x1, y1, color);
        if (x1 == x2 && y1 == y2) break;
        e2 = 2 * err;
        if (e2 >= dy) { err += dy; x1 += sx; }
        if (e2 <= dx) { err += dx; y1 += sy; }
    }
}

/*---------------- 画坐标轴 ----------------*/
static void draw_axis(void)
{
    /* Y 轴竖线 */
    draw_line(CHART_X0, CHART_Y0, CHART_X0, CHART_Y0 + CHART_H - 1, AXIS_COLOR);
    /* X 轴横线 */
    draw_line(CHART_X0, CHART_Y0 + CHART_H - 1,
              CHART_X0 + CHART_W - 1, CHART_Y0 + CHART_H - 1, AXIS_COLOR);
}

/*---------------- 画标题 ----------------*/
static void draw_title(void)
{
    uint16_t start_x = CHART_X0 + (CHART_W - 8 * 16) / 2;
    display_title16(start_x, CHART_Y0 - 18, TITLE_COLOR, "实时光照强度折线图");
}

/*---------------- 清空折线区域 ----------------*/
static void clear_line_area(void)
{
    TFT_SEND_CMD(0x2A);
    TFT_SEND_DATA(CHART_X0 >> 8); TFT_SEND_DATA(CHART_X0);
    TFT_SEND_DATA((CHART_X0 + CHART_W - 1) >> 8); TFT_SEND_DATA(CHART_X0 + CHART_W - 1);

    TFT_SEND_CMD(0x2B);
    TFT_SEND_DATA(CHART_Y0 >> 8); TFT_SEND_DATA(CHART_Y0);
    TFT_SEND_DATA((CHART_Y0 + CHART_H - 1) >> 8); TFT_SEND_DATA(CHART_Y0 + CHART_H - 1);

    TFT_SEND_CMD(0x2C);
    for (uint32_t i = 0; i < CHART_W * CHART_H; i++) {
        TFT_SEND_DATA(0x00); TFT_SEND_DATA(0x00); TFT_SEND_DATA(0x00);
    }
}

/*---------------- 初始化 ----------------*/
void linechart_init(void)
{
    clear_line_area();   /* 先清折线区域 */
    draw_axis();         /* 再画坐标轴 */
    draw_title();        /* 再画标题 */
}

/*---------------- 实时更新 ----------------*/
void linechart_update(uint32_t vout_mv)
{
    /* 将电压映射为 Y 坐标（电压越大，Y 越小） */
    uint16_t y_cur = CHART_Y0 + CHART_H - 1 - (vout_mv * CHART_H / VREF_MAX);
    if (y_cur < CHART_Y0) y_cur = CHART_Y0;
    if (y_cur >= CHART_Y0 + CHART_H) y_cur = CHART_Y0 + CHART_H - 1;

    /* 画折线 */
    draw_line(CHART_X0 + x_last, y_last, CHART_X0 + x_cur, y_cur, LINE_COLOR);

    x_last = x_cur;
    y_last = y_cur;
    x_cur += PIX_PER_SEC;

    if (x_cur >= CHART_W) {
        x_cur = 0;
        x_last = 0;                 /* 复位起点 */
        y_last = CHART_Y0 + CHART_H / 2;
        clear_line_area();          /* 仅清折线区，保留坐标轴和标题 */
    }
}
